/*
 * Copyright (c) 2012 OptiCare Systems Ltd
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * Authors: Kevin Martin (kev82@khn.org.uk)
 */
#include <lua5.2/lua.hpp>
#include <lua5.2/lauxlib.h>
#include "luaOE.hpp"

extern "C" {
	int luaopen_sandbox(lua_State *l);
}

static int api_run_sandbox(lua_State *l) {
	if(lua_gettop(l) != 1) {
		luaL_error(l, "Expected 1 argument");
	}

	luaL_checkstring(l, 1);

	lua_State *s = luaL_newstate();
	luaL_openlibs(s);

	if(luaL_dostring(s, lua_tostring(l, -1)) != LUA_OK) {
		luaL_error(l, "Sandbox Issue: %s", lua_tostring(s, -1));
	}

	int nrv = lua_gettop(s);
	for(int i=1;i!=nrv+1;++i) {
		boost::shared_ptr<luaOE_serialized_obj> so = luaOE_serialize(s, i);
		so->unserializeState(l);
	}

	lua_close(s);
	return nrv;
}

static int api_table2string(lua_State *l) {
	lua_settop(l, 1);
	luaL_checktype(l, 1, LUA_TTABLE);

	try {
		std::string s = luaOE_serialize(l, 1)->unserializeLuaString();
		lua_pushstring(l, s.c_str());
		return 1;
	} catch (std::exception &e) {
		luaL_error(l, "Serialization failed: %s", e.what());
	}

	assert("unreachable code" == 0x0);
	throw std::logic_error("Unreachable Code");
}

static int api_copy(lua_State *l) {
	if(lua_gettop(l) != 1) {
		luaL_error(l, "Expected one argument");
	}

	try {
		luaOE_serialize(l, 1)->unserializeState(l);
		return 1;
	} catch (std::exception &e) {
		luaL_error(l, "Couldn't serialize/deserialize: `%s'", e.what());
	}

	assert("unreachable code" == 0x0);
	throw std::logic_error("Unreachable Code");
}

static const luaL_Reg sandbox_funcs[] = {
	{"run", api_run_sandbox},
	{"table2string", api_table2string},
	{"copy", api_copy},
	{NULL, NULL}
};

int luaopen_sandbox(lua_State *l) {
	luaL_newlib(l, sandbox_funcs);
	return 1;
}
